/*

Miranda IM: the free IM client for Microsoft* Windows*

Copyright 2000-2007 Miranda ICQ/IM project, 
all portions of this codebase are copyrighted to the people 
listed in contributors.txt.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
aLONG with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

#include "commonheaders.h"

#ifdef _UNICODE
 #include <dlgs.h>
#endif

#include "m_db3xSA.h"

/***********************************************************************************************************
 * namespace NExImport
 ***********************************************************************************************************/
namespace NExImport {
/***********************************************************************************************************/

#ifdef _UNICODE

#define HKEY_MIRANDA_PLACESBAR	_T("Software\\Miranda IM\\PlacesBar")
#define HKEY_WINPOL_PLACESBAR	_T("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\ComDlg32\\PlacesBar")

static WNDPROC	DefPlacesBarProc;

/**
 * name:		InitAlteredPlacesBar
 * namespace:	NExImport
 * desc:		It mapps the current users registry to a dummy key and
 *				changes the policy hive which is responsible for the places to be displayed,
 *				so the desired places are visible.
 * params:		nothing
 * return:		nothing
 **/
static VOID InitAlteredPlacesBar()
{
	HKEY hkMiranda;
	LONG result;

	// do not try it on a win9x Box
	if(!IsWinVer2000Plus())
		return;

	// create or open temporary hive for miranda specific places
	result = RegCreateKey(HKEY_CURRENT_USER, HKEY_MIRANDA_PLACESBAR, &hkMiranda);
	if(SUCCEEDED(result)) {
		HKEY hkPlacesBar;

		// map the current users registry
		RegOverridePredefKey(HKEY_CURRENT_USER, hkMiranda);
		// open the policy key
		result = RegCreateKey(HKEY_CURRENT_USER, HKEY_WINPOL_PLACESBAR, &hkPlacesBar);
		// install the places bar
		if(SUCCEEDED(result)) {
			DWORD dwFolderID;
			LPSTR p;
			CHAR szMirandaPath[MAX_PATH];
			CHAR szProfilePath[MAX_PATH];

			// default places: Desktop, My Documents, My Computer
			dwFolderID = 0;	 RegSetValueEx(hkPlacesBar, _T("Place0"), 0, REG_DWORD, (PBYTE)&dwFolderID, sizeof(DWORD));
			dwFolderID = 5;  RegSetValueEx(hkPlacesBar, _T("Place1"), 0, REG_DWORD, (PBYTE)&dwFolderID, sizeof(DWORD));
			dwFolderID = 17; RegSetValueEx(hkPlacesBar, _T("Place2"), 0, REG_DWORD, (PBYTE)&dwFolderID, sizeof(DWORD));

			// Miranda's installation path
			GetModuleFileNameA(GetModuleHandle(NULL), szMirandaPath, SIZEOF(szMirandaPath)); 
			if(p = mir_strrchr(szMirandaPath, '\\')) {
				ZeroMemory(p, sizeof(szMirandaPath) - (p - szMirandaPath));
				RegSetValueExA(hkPlacesBar, "Place3", 0, REG_SZ, (PBYTE)szMirandaPath, (p - szMirandaPath) + 2);
			}

			// Miranda's profile path
			ZeroMemory(szProfilePath, sizeof(szProfilePath));
			CallService(MS_DB_GETPROFILEPATH, SIZEOF(szProfilePath), (LPARAM)szProfilePath);
			// only add if different from profile path
			RegSetValueExA(hkPlacesBar, "Place4", 0, REG_SZ, (PBYTE)szProfilePath, strlen(szProfilePath) + 1);

			RegCloseKey(hkPlacesBar);
		}
		RegCloseKey(hkMiranda);
	}
}

/**
 * name:		ResetAlteredPlaceBars
 * namespace:	NExImport
 * desc:		Remove the mapping of current users registry
 *				and delete the temporary registry hive
 * params:		nothing
 * return:		nothing
 **/
static VOID ResetAlteredPlaceBars()
{
	// make sure not to call the following on a Win9x Box
	if(IsWinVer2000Plus()) {
		RegOverridePredefKey(HKEY_CURRENT_USER, NULL);
		SHDeleteKey(HKEY_CURRENT_USER, HKEY_MIRANDA_PLACESBAR);
	}
}

/**
 * name:		PlacesBarSubclassProc
 * namespace:	NExImport
 * params:		hWnd	- handle, to control's window
 *				uMsg	- the message to handle
 *				wParam	- message dependend parameter
 *				lParam	- message dependend parameter
 * return:		depends on message
 **/
static LRESULT PlacesBarSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch(uMsg) {
		case TB_ADDBUTTONS: {
			TBBUTTON *tbb = (TBBUTTON *)lParam;
			TCHAR szBtnText[MAX_PATH];
			INT iString;
			HWND hWndToolTip;

			if(tbb) {
				switch(tbb->idCommand) {
					// miranda button
					case 41063:
						ZeroMemory(szBtnText, sizeof(szBtnText));
						mir_sntprintf(szBtnText, SIZEOF(szBtnText), _T("%s"), TranslateT("Miranda IM"));
						iString = SendMessage(hWnd, TB_ADDSTRING, NULL, (LPARAM)szBtnText);
						if(iString != -1) tbb->iString = iString;
						// set tooltip
						hWndToolTip = (HWND)SendMessage(hWnd, TB_GETTOOLTIPS, NULL, NULL);
						if(hWndToolTip) {
							TOOLINFO ti;

							ZeroMemory(&ti, sizeof(ti));
							ti.cbSize = sizeof(ti);
							ti.hwnd = hWnd;
							ti.lpszText = TranslateT("Shows Miranda's installation directory.");
							ti.uId = tbb->idCommand;
							SendMessage(hWndToolTip, TTM_ADDTOOL, NULL, (LPARAM)&ti);
						}
						break;
					// profile button
					case 41064:
						// set button text
						ZeroMemory(szBtnText, sizeof(szBtnText));
						mir_sntprintf(szBtnText, SIZEOF(szBtnText), _T("%s"), TranslateT("Profile"));
						iString = SendMessage(hWnd, TB_ADDSTRING, NULL, (LPARAM)szBtnText);
						if(iString != -1) tbb->iString = iString;

						// set tooltip
						hWndToolTip = (HWND)SendMessage(hWnd, TB_GETTOOLTIPS, NULL, NULL);
						if(hWndToolTip) {
							TOOLINFO ti;

							ZeroMemory(&ti, sizeof(ti));
							ti.cbSize = sizeof(ti);
							ti.hwnd = hWnd;
							ti.lpszText = TranslateT("Shows the directory with all your Miranda's profiles.");
							ti.uId = tbb->idCommand;
							SendMessage(hWndToolTip, TTM_ADDTOOL, NULL, (LPARAM)&ti);
						}
						// unmap registry and delete keys
						ResetAlteredPlaceBars();
						break;
				}
			}
			break;
		}
	}
	return CallWindowProc(DefPlacesBarProc, hWnd, uMsg, wParam,lParam);
}

/**
 * name:		OpenSaveFileDialogHook
 * namespace:	NExImport
 * desc:		it subclasses the places bar to provide the own interface for adding places
 * params:		hDlg	- handle, to control's window
 *				uMsg	- the message to handle
 *				wParam	- message dependend parameter
 *				lParam	- message dependend parameter
 * return:		depends on message
 **/
static UINT_PTR CALLBACK OpenSaveFileDialogHook(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch(uMsg) {
		case WM_NOTIFY:
			if(((LPNMHDR)lParam)->code == CDN_INITDONE) {
				HWND hPlacesBar = GetDlgItem(GetParent(hDlg), ctl1);

				// we have a places bar?
				if(hPlacesBar != NULL) {
					InitAlteredPlacesBar();
					// finally subclass the places bar
					DefPlacesBarProc = SubclassWindow(hPlacesBar, PlacesBarSubclassProc);
				}
			}
			break;
		case WM_DESTROY:
			// unmap registry and delete keys 
			// (is to make it sure, if somehow the last places button was not added which also calls this function)
			ResetAlteredPlaceBars();
			break;
	}
	return FALSE;
}

#endif

/**
 * name:		GetInitialDir
 * namespace:	NExImport
 * desc:		read the last vCard directory from database
 *				pszInitialDir	- buffer to store the initial dir to (size must be MAX_PATH)
 * return:		nothing
 **/
static VOID GetInitialDir(LPSTR pszInitialDir)
{
	CHAR szRelative[MAX_PATH];

	ZeroMemory(szRelative, SIZEOF(szRelative));

	// is some standard path defined
	if(!DBGetSettingStaticString(0, MODNAME, "vCardPath", szRelative, SIZEOF(szRelative))) {
		if(!CallService(MS_UTILS_PATHTOABSOLUTE, (WPARAM)szRelative, (WPARAM)pszInitialDir))
			strcpy(pszInitialDir, szRelative);
	}
	else
	if(
		// try to use environment variables supported by pathpatch of db3xSA
		!ServiceExists(MS_DB_GETPROFILEPATH_BASIC) ||		
		!CallService(MS_UTILS_PATHTOABSOLUTE, (WPARAM)PROFILEPATH "\\" PROFILENAME, (WPARAM)pszInitialDir)
	  )
	{
		// use standard path to absolute
		if(!CallService(MS_UTILS_PATHTOABSOLUTE, (WPARAM)"", (WPARAM)pszInitialDir))
			*pszInitialDir = 0;
	}
	else
		*pszInitialDir = 0;
}

/**
 * name:		SaveInitialDir
 * namespace:	NExImport
 * desc:		save the last vCard directory from database
 *				pszInitialDir	- buffer to store the initial dir to (size must be MAX_PATH)
 * return:		nothing
 **/
static VOID SaveInitialDir(LPSTR pszInitialDir)
{
	CHAR szRelative[MAX_PATH];
	LPSTR p;

	if(p = mir_strrchr(pszInitialDir, '\\')) {
		*p = 0;
		if(CallService(MS_UTILS_PATHTORELATIVE, (WPARAM)pszInitialDir, (LPARAM)szRelative))
			DBWriteContactSettingString(0, MODNAME, "vCardPath", szRelative);
		else
			DBWriteContactSettingString(0, MODNAME, "vCardPath", pszInitialDir);
		*p = '\\';
	}	
}

/**
 * name:		InitOpenFileNameStruct
 * namespace:	NExImport
 * desc:		initialize the openfilename structure
 * params:		pofn			- OPENFILENAME structure to initialize
 *				hWndParent		- parent window
 *				pszTitle		- title for the dialog
 *				pszFilter		- the filters to offer
 *				pszInitialDir	- buffer to store the initial dir to (size must be MAX_PATH)
 *				pszFile			- this is the buffer to store the file to (size must be MAX_PATH)
 * return:		nothing
 **/
static VOID InitOpenFileNameStruct(OPENFILENAMEA *pofn, HWND hWndParent, LPCSTR pszTitle, LPCSTR pszFilter, LPSTR pszInitialDir, LPSTR pszFile)
{
	ZeroMemory(pofn, sizeof(OPENFILENAME));

	pofn->Flags			  = OFN_NONETWORKBUTTON|OFN_ENABLESIZING;
	pofn->hwndOwner		  = hWndParent;
	pofn->lpstrTitle	  = pszTitle;
	pofn->lpstrFilter	  = pszFilter;
	pofn->lpstrFile		  = pszFile;
	pofn->nMaxFile		  = MAX_PATH;
	pofn->lpstrDefExt	  = "xml";

	GetInitialDir(pszInitialDir);
	pofn->lpstrInitialDir = pszInitialDir;

#ifdef _UNICODE
	if(IsWinVer2000Plus()) {
		pofn->lStructSize = sizeof (OPENFILENAME);
		pofn->Flags		 |= OFN_ENABLEHOOK|OFN_EXPLORER;
		pofn->lpfnHook	  = (LPOFNHOOKPROC)OpenSaveFileDialogHook;
	}
	else {
		pofn->lStructSize = OPENFILENAME_SIZE_VERSION_400;
	}
#else
	pofn->lStructSize = sizeof (OPENFILENAME);
#endif
}


/**
 * name:		MyGetOpenFileName
 * namespace:	NExImport
 * desc:		displayes a slightly modified OpenFileName DialogBox
 * params:		hWndParent		- parent window
 *				pszTitle		- title for the dialog
 *				pszFilter		- the filters to offer
 *				pszFile			- this is the buffer to store the file to (size must be MAX_PATH)
 * return:		-1 on error/abort or filter index otherwise
 **/
INT MyGetOpenFileName(HWND hWndParent, LPCSTR pszTitle, LPCSTR pszFilter, LPSTR pszFile)
{
	OPENFILENAMEA ofn;
	CHAR szInitialDir[MAX_PATH];

	InitOpenFileNameStruct(&ofn, hWndParent, pszTitle, pszFilter, szInitialDir, pszFile);
	ofn.Flags |= OFN_PATHMUSTEXIST;
	if(!GetOpenFileNameA(&ofn)) {
		DWORD dwError = CommDlgExtendedError();
		if(dwError) MsgErr(ofn.hwndOwner, _T("The OpenFileDialog returned an error: %d!"), dwError);
		return -1;
	}
	SaveInitialDir(pszFile);
	return ofn.nFilterIndex;
}

/**
 * name:		MyGetSaveFileName
 * namespace:	NExImport
 * desc:		displayes a slightly modified SaveFileName DialogBox
 * params:		hWndParent		- parent window
 *				pszTitle		- title for the dialog
 *				pszFilter		- the filters to offer
 *				pszFile			- this is the buffer to store the file to (size must be MAX_PATH)
 * return:		-1 on error/abort or filter index otherwise
 **/
INT MyGetSaveFileName(HWND hWndParent, LPCSTR pszTitle, LPCSTR pszFilter, LPSTR pszFile)
{
	OPENFILENAMEA ofn;
	CHAR szInitialDir[MAX_PATH];

	InitOpenFileNameStruct(&ofn, hWndParent, pszTitle, pszFilter, szInitialDir, pszFile);
	ofn.Flags |= OFN_OVERWRITEPROMPT;

	if(!GetSaveFileNameA(&ofn)) {
		DWORD dwError = CommDlgExtendedError();

		if(dwError) MsgErr(ofn.hwndOwner, _T("The SaveFileDialog returned an error: %d!"), dwError);
		return -1;
	}
	SaveInitialDir(pszFile);
	return ofn.nFilterIndex;
}

} // namespace NExImport